package com.cdks.wuxiu.api.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;

import com.cdks.wuxiu.api.component.agora.AgoraUtil;
import com.cdks.wuxiu.api.component.aliyun.CloudStorage;
import com.cdks.wuxiu.api.component.cdks.kmsg.Auth;
import com.cdks.wuxiu.api.model.dto.CloudStorageDTO;
import com.cdks.wuxiu.api.model.dto.KmsgDataDTO;
import com.cdks.wuxiu.api.model.vo.AuthGetUserTokenVO;
import com.cdks.wuxiu.api.service.redis.RedisService;
import com.cdks.wuxiu.api.util.AuthUtils;
import com.cdks.wuxiu.api.util.TimeUtils;
import com.cdks.wuxiu.common.component.constant.ApiCodeEnum;
import com.cdks.wuxiu.common.exception.ApiException;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


@Slf4j
@Service
public class AuthServiceImpl implements AuthService {
    @Resource
    private RedisService redisService;
    

    private String setChalln(long userId) {
        String challn  = String.valueOf(RandomUtil.randomInt(100000, 999999));
        // 缓存 challn
        boolean ret  = redisService.setChalln(userId, challn);
        if (ret)
        {
            return challn;
        }

        // 有可能在临界点，上面setChalln失败后，challn刚好过期，所以要做判断
        String redisChalln  = redisService.getChalln(userId);
        if (redisChalln == null)
        {
            redisService.setChalln(userId, challn);

            return challn;
        }

        return redisChalln;
    }

    @Override
    public String setUserToken(long userId, boolean force) {
        // 生成 Token
        String original  = String.valueOf(userId + TimeUtils.getTimeSecond());
        String token  =  SecureUtil.md5(original);
        
        // 缓存 Token
        boolean ret  = redisService.setUserToken(userId, token, force);
        if (ret)
        {
            return token;
        }

        token  = redisService.getUserToken(userId);
        // 有可能在临界点，上面setUserToken后，token刚好过期，所以要做判断
        if (token == null)
        {
            AuthGetUserTokenVO vo  = new AuthGetUserTokenVO();
            vo.setChalln(setChalln(userId));

            throw new ApiException(ApiCodeEnum.TOKEN_ERROR, vo);
        }

        return token;
    }

    @Override
    public String getUserToken(long userId, long nonce, String challn) {
        //校验 challn
        String redisChalln = redisService.getChalln(userId);
        String encChalln  = AuthUtils.encryptChalln(userId, nonce, redisChalln);
        if ((redisChalln == null) || (!challn.equals(encChalln)))
        {
            log.info("传入参数：userId = " + userId + ", nonce = " + nonce + ", challn = " + challn);
            log.info("校验失败：redisChalln = " + redisChalln + " => encChalln = " + encChalln);

            AuthGetUserTokenVO vo  = new AuthGetUserTokenVO();
            vo.setChalln(setChalln(userId));
    
            throw new ApiException(ApiCodeEnum.TOKEN_ERROR, vo);
        }

        // 生成 Token
        return setUserToken(userId, false);
    }

    @Override
    public int delUserToken(long userId) {
        return redisService.delUserToken(userId);
    }

    @Override
    public int checkUserToken(long userId, long nonce, String token) {
        String redisToken  = redisService.getUserToken(userId);
        //校验 Token
        //token失效 返回挑战码
        if (redisToken == null)
        {
            AuthGetUserTokenVO vo  = new AuthGetUserTokenVO();
            vo.setChalln(setChalln(userId));

            throw new ApiException(ApiCodeEnum.TOKEN_ERROR, vo);
        }

        //token不一致，已在其他设备登录
        String encToken  = AuthUtils.encryptToken(userId, nonce, redisToken);
        if (!token.equals(encToken))
        {
            log.info("传入参数：userId = " + userId + ", nonce = " + nonce + ", token = " + token);
            log.info("校验失败：redisToken = " + redisToken + " => encToken = " + encToken);

            throw new ApiException(ApiCodeEnum.OTHER_LOGIN);
        }
        
        return 0;
    }
        
    @Override
    public CloudStorageDTO getOssAuthData() {
        String sts = redisService.getOssAuthData();
        if (sts != null)
        {
            return JSONUtil.toBean(sts, CloudStorageDTO.class);
        }

        CloudStorageDTO dto  = CloudStorage.getAuthData();
        redisService.setOssAuthData(dto);

        return dto;
    }

    @Override
    public KmsgDataDTO getKmsgData(long userId) {
        String data = redisService.getKmsgAuthData(userId);
        if (data != null)
        {
            return JSONUtil.toBean(data, KmsgDataDTO.class);
        }

        KmsgDataDTO dto  = Auth.getKmsgAuthData(userId);
        redisService.setKmsgAuthData(userId, dto);

        return dto;
    }
        
    @Override
    public String getCallToken(long userId, String ucid) {
        String callToken  = redisService.getCallToken(userId, ucid);
        if (callToken == null)
        {
            callToken  = AgoraUtil.getCallToken(String.valueOf(userId), ucid);
        }

        if (callToken != null)
        {
            redisService.setCallToken(userId, ucid, callToken);
        }

        return callToken;
    }
}
